package club.jdiy.core.base;

import club.jdiy.core.ex.JDiyConvertException;
import club.jdiy.core.ex.JDiyException;
import club.jdiy.utils.BeanUtils;
import club.jdiy.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * JDiy JPA result Transformer
 *
 * @author ziquee(子秋) QQ号:39886616 主页: http://www.jdiy.club
 * @version 20201020
 */
@Slf4j
class Transformer extends AliasedTupleSubsetResultTransformer {
    private final Class<?> resultClass;

    public Transformer(Class<?> resultClass) {
        Objects.requireNonNull(resultClass, "resultClass cannot be null");
        this.resultClass = resultClass;
    }

    @Override
    public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
        return false;
    }

    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        Object result;
        try {
            result = Map.class.isAssignableFrom(resultClass) ? new HashMap<>() : resultClass.getDeclaredConstructor().newInstance();
            Object v;
            int i = 0;
            while (i < aliases.length) {
                if (StringUtils.isEmpty(aliases[i])) throw new JDiyException("Query alias is null. column index: " + i);
                BeanUtils.set(result, aliases[i], (v = tuple[i]) instanceof Clob ? clobToString((Clob) v) : v);
                i++;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new JDiyConvertException(e.getMessage());
        }
        return result;
    }

    private static String clobToString(Clob clob) {
        String reString = "";
        try (Reader is = clob.getCharacterStream()) {
            try (BufferedReader br = new BufferedReader(is)) {
                reString = br.lines().collect(Collectors.joining());
            }
        } catch (SQLException | IOException e) {
            log.error("Get Clob Content Failed", e);
        }
        return reString;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        return resultClass.equals(((Transformer) o).resultClass);
    }

    @Override
    public int hashCode() {
        return 31* resultClass.hashCode();
    }
}